 1.ClickHouse之选择查询附录
   
   1).with子句
   本节提供对公共表表达式的支持 (CTE），所以结果 WITH 子句可以在其余部分中使用 SELECT 查询。
   限制
       1. 不支持递归查询。
       2. 当在section中使用子查询时，它的结果应该是只有一行的标量。
       3. Expression的结果在子查询中不可用。
   例 示例1: 使用常量表达式作为 "variable"
hdp-1 :) with '2020-08-02 14:20:22' as tm select toDate(tm);
WITH '2020-08-02 14:20:22' AS tm
SELECT toDate(tm)
┌─toDate(tm)─┐
│ 2020-08-02 │
└────────────┘
1 rows in set. Elapsed: 0.002 sec.
WITH '2019-08-01 15:23:00' as ts_upper_bound
SELECT *
FROM hits
WHERE
EventDate = toDate(ts_upper_bound) AND
EventTime <= ts_upper_bound

   示例2: 从SELECT子句列表中逐出sum(bytes)表达式结果
WITH sum(bytes) as s
SELECT
formatReadableSize(s),
table
FROM system.parts
GROUP BY table
ORDER BY s

   例3: 使用标量子查询的结果
   没有 where acitive条件限制
hdp-1 :) with sum(bytes) as s
:-] select formatReadableSize(s) from parts;
WITH sum(bytes) AS s
SELECT formatReadableSize(s)
FROM parts
┌─formatReadableSize(s)─┐
│ 1.36 GiB │
└───────────────────────┘
1 rows in set. Elapsed: 0.009 sec.
   
   有where active条件限制
hdp-1 :) with sum(bytes) as s
:-] select formatReadableSize(s)
:-] from parts
:-] where active;
WITH sum(bytes) AS s
SELECT formatReadableSize(s)
FROM parts
WHERE active
┌─formatReadableSize(s)─┐
│ 1.24 GiB │
└───────────────────────┘
1 rows in set. Elapsed: 0.003 sec.

   -- 不用with定义变量的写法
hdp-1 :) select formatReadableSize(sum(bytes)) as f, table from parts group by table;
SELECT
formatReadableSize(sum(bytes)) AS f,
table
FROM parts
GROUP BY table
┌─f──────────┬─table───────────────────┐
│ 11.62 KiB │ mt_table │
│ 277.00 B │ r1 │
│ 1.18 GiB │ hits_v1 │
│ 182.74 MiB │ metric_log │
│ 1.49 MiB │ hot_cold_table │
│ 1.14 KiB │ partition_v1 │
│ 38.65 KiB │ trace_log │
│ 185.61 KiB │ query_thread_log │
│ 1.50 KiB │ mt_table2 │
│ 1.26 KiB │ summing_table │
│ 189.00 B │ ttl_table_v1 │
│ 189.25 KiB │ query_log │
│ 233.00 B │ jbod_table │
│ 553.00 B │ replace_table │
│ 900.00 B │ partition_v2 │
│ 1.01 MiB │ hot_cold_table_new │
│ 4.92 MiB │ asynchronous_metric_log │
└────────────┴─────────────────────────┘
17 rows in set. Elapsed: 0.010 sec.

   相同结果，用with定义变量
hdp-1 :) with sum(bytes) as a select formatReadableSize(a) as s,table from parts group by
table;
WITH sum(bytes) AS a
SELECT
formatReadableSize(a) AS s,
table
FROM parts
GROUP BY table
┌─s──────────┬─table───────────────────┐
│ 11.62 KiB │ mt_table │
│ 277.00 B │ r1 │
│ 1.18 GiB │ hits_v1 │
│ 182.37 MiB │ metric_log │
│ 1.49 MiB │ hot_cold_table │
│ 1.14 KiB │ partition_v1 │
│ 38.65 KiB │ trace_log │
│ 228.61 KiB │ query_thread_log │
│ 1.50 KiB │ mt_table2 │
│ 1.26 KiB │ summing_table │
│ 189.00 B │ ttl_table_v1 │
│ 230.87 KiB │ query_log │
│ 233.00 B │ jbod_table │
│ 553.00 B │ replace_table │
│ 900.00 B │ partition_v2 │
│ 1.01 MiB │ hot_cold_table_new │
│ 4.92 MiB │ asynchronous_metric_log │
└────────────┴─────────────────────────┘
17 rows in set. Elapsed: 0.014 sec.
/* this example would return TOP 10 of most huge tables */
WITH
(
SELECT sum(bytes)
FROM system.parts
WHERE active
) AS total_disk_usage
SELECT
(sum(bytes) / total_disk_usage) * 100 AS table_disk_usage,
table
FROM system.parts
GROUP BY table
ORDER BY table_disk_usage DESC
LIMIT 10

   例4: 在子查询中重用表达式
   作为子查询中表达式使用的当前限制的解决方法，您可以复制它。
WITH ['hello'] AS hello
SELECT
hello,
*
FROM
(
WITH ['hello'] AS hello
SELECT hello
)
┌─hello─────┬─hello─────┐
│ ['hello'] │ ['hello'] │
└───────────┴───────────┘
   2).FROM子句
   FROM 子句指定从以下数据源中读取数据:
       表
       子查询
       表函数
   JOIN 和 ARRAY JOIN 子句也可以用来扩展 FROM 的功能
   子查询是另一个 SELECT 可以指定在 FROM 后的括号内的查询。
   FROM 子句可以包含多个数据源，用逗号分隔，这相当于在他们身上执行 CROSS JOIN
   FINAL 修饰符
   当 FINAL 被指定，ClickHouse会在返回结果之前完全合并数据，从而执行给定表引擎合并期间发生的所有数据转
换。
   它适用于从使用 MergeTree-引擎族（除了 GraphiteMergeTree). 还支持:
       Replicated 版本 MergeTree 引擎
	   View, Buffer, Distributed，和 MaterializedView 在其他引擎上运行的引擎，只要是它们底层是 MergeTree-引
擎表即可。
   缺点
   使用的查询 FINAL 执行速度不如类似的查询那么快，因为:
       查询在单个线程中执行，并在查询执行期间合并数据。
       查询与 FINAL 除了读取查询中指定的列之外，还读取主键列。
   在大多数情况下，避免使用 FINAL. 常见的方法是使用假设后台进程的不同查询 MergeTree 引擎还没有发生，并通过
应用聚合（例如，丢弃重复项）来处理它。
   实现细节
   如果 FROM 子句被省略，数据将从读取 system.one 表。 该 system.one 表只包含一行（此表满足与其他 DBMS 中
的 DUAL 表有相同的作用）。
   若要执行查询，将从相应的表中提取查询中列出的所有列。 外部查询不需要的任何列都将从子查询中抛出。 如果查
询未列出任何列（例如, SELECT count() FROM t），无论如何都会从表中提取一些列（首选是最小的列），以便计算
行数。
   3).SAMPLE 子句
   该 SAMPLE 子句允许近似于 SELECT 查询处理。
   启用数据采样时，不会对所有数据执行查询，而只对特定部分数据（样本）执行查询。 例如，如果您需要计算所有
访问的统计信息，只需对所有访问的1/10 分数执行查询，然后将结果乘以10即可。
   近似查询处理在以下情况下可能很有用:
       当你有严格的时间需求（如<100ms)，但你不能通过额外的硬件资源来满足他们的成本。
       当您的原始数据不准确时，所以近似不会明显降低质量。
       业务需求的目标是近似结果（为了成本效益，或者向高级用户推销确切结果）。
   注
   您只能使用采样中的表 MergeTree 族，并且只有在表创建过程中指定了采样表达式（请参阅 MergeTree引擎).
   下面列出了数据采样的功能:
       数据采样是一种确定性机制。 同样的结果 SELECT .. SAMPLE 查询始终是相同的。
	   对于不同的表，采样工作始终如一。 对于具有单个采样键的表，具有相同系数的采样总是选择相同的可能数据
子集。 例如，用户Id的示例采用来自不同表的所有可能的用户Id的相同子集的行。 这意味着您可以在子查询中
使用采样 IN 此外，您可以使用 JOIN 。
       采样允许从磁盘读取更少的数据。 请注意，您必须正确指定采样键。 有关详细信息，请参阅 创建MergeTree
表.
   为 SAMPLE 子句支持以下语法:
   SAMPLE Clause Syntax      产品描述
   SAMPLE k             这里 k 是从0到1的数字。
   
   查询执行于 k SAMPLE 0.1Read moreSAMPLE n n n SAMPLE 10000000Read moreSAMPLE k OFFSET
m k m k mRead more
   SAMPLE K
   这里 k 从0到1的数字（支持小数和小数表示法）。 例如, SAMPLE 1/2 或 SAMPLE 0.5.
   注意：为了得到最终的统计结果，需要将sample查询结果乘系数
   在一个 SAMPLE k 子句，样品是从 k 数据的分数。 示例如下所示:
hdp-1 :) select count(CounterID) from hits_v1 sample 0.1;
SELECT count(CounterID)
FROM hits_v1
SAMPLE 1 / 10
┌─count(CounterID)─┐
│ 839889 │
└──────────────────┘
1 rows in set. Elapsed: 0.033 sec. Processed 7.36 million rows, 88.30 MB (223.32 million
rows/s., 2.68 GB/s.)

hdp-1 :) select count(CounterID) from hits_v1;
SELECT count(CounterID)
FROM hits_v1
┌─count(CounterID)─┐
│ 8873898 │
└──────────────────┘
1 rows in set. Elapsed: 0.015 sec. Processed 8.87 million rows, 35.50 MB (579.86 million
rows/s., 2.32 GB/s.)

   利用虚拟字段_sample_factor来获取采样系数

hdp-1 :) select CounterID,_sample_factor from hits_v1 sample 0.1 limit 2;
SELECT
CounterID,
_sample_factor
FROM hits_v1
SAMPLE 1 / 10
LIMIT 2
┌─CounterID─┬─_sample_factor─┐
│ 57 │ 10 │
└───────────┴────────────────┘
┌─CounterID─┬─_sample_factor─┐
│ 57 │ 10 │
└───────────┴────────────────┘
2 rows in set. Elapsed: 0.004 sec.

hdp-1 :) select CounterID,_sample_factor from hits_v1 limit 2;
SELECT
CounterID,
_sample_factor
FROM hits_v1
LIMIT 2
┌─CounterID─┬─_sample_factor─┐
│ 57 │ 1 │
│ 57 │ 1 │
└───────────┴────────────────┘
2 rows in set. Elapsed: 0.003 sec.

hdp-1 :) select CounterID,_sample_factor from hits_v1 sample 0.2 limit 2;
SELECT
CounterID,
_sample_factor
FROM hits_v1
SAMPLE 2 / 10
LIMIT 2
┌─CounterID─┬─_sample_factor─┐
│ 57 │ 5 │
└───────────┴────────────────┘
┌─CounterID─┬─_sample_factor─┐
│ 57 │ 5 │
└───────────┴────────────────┘
2 rows in set. Elapsed: 0.006 sec.

SELECT
Title,
count() * 10 AS PageViews
FROM hits_distributed
SAMPLE 0.1
WHERE
CounterID = 34
GROUP BY Title
ORDER BY PageViews DESC LIMIT 1000

   在此示例中，对0.1(10%)数据的样本执行查询。 聚合函数的值不会自动修正，因此要获得近似结果，值 count() 手动
乘以10。
   SAMPLE N
   这里 n 是足够大的整数。 例如, SAMPLE 10000000.
   在这种情况下，查询在至少一个样本上执行 n 行（但不超过这个）。 例如, SAMPLE 10000000 在至少10,000,000行
上运行查询。
   由于数据读取的最小单位是一个颗粒（其大小由 index_granularity 设置），是有意义的设置一个样品，其大小远大
于颗粒。
   使用时 SAMPLE n 子句，你不知道处理了哪些数据的相对百分比。 所以你不知道聚合函数应该乘以的系数。 使用
_sample_factor 虚拟列得到近似结果。
   该 _sample_factor 列包含动态计算的相对系数。 当您执行以下操作时，将自动创建此列 创建 具有指定采样键的
表。 的使用示例 _sample_factor 列如下所示。
hdp-1 :) select count() from hits_v1 sample 10000;
SELECT count()
FROM hits_v1
SAMPLE 10000
┌─count()─┐
│ 9251 │
└─────────┘
1 rows in set. Elapsed: 0.066 sec. Processed 7.15 million rows, 119.16 MB (108.92 million
rows/s., 1.82 GB/s.)

hdp-1 :) select CounterID,_sample_factor from hits_v1 sample 10000 limit 1;
SELECT
CounterID,
_sample_factor
FROM hits_v1
SAMPLE 10000
LIMIT 1
┌─CounterID─┬─_sample_factor─┐
│ 1294 │ 886.3744 │
└───────────┴────────────────┘
1 rows in set. Elapsed: 0.045 sec. Processed 7.07 thousand rows, 84.88 KB (156.61 thousand
rows/s., 1.88 MB/s.)
   让我们考虑表 visits，其中包含有关网站访问的统计信息。 第一个示例演示如何计算页面浏览量:
hdp-1 :) select sum(PageViews) from visits_v1;
SELECT sum(PageViews)
FROM visits_v1
┌─sum(PageViews)─┐
│ 6738137 │
└────────────────┘
1 rows in set. Elapsed: 0.010 sec. Processed 1.68 million rows, 6.71 MB (160.58 million
rows/s., 642.32 MB/s.)

hdp-1 :) select sum(PageViews * _sample_factor) from visits_v1 sample 10000000;
SELECT sum(PageViews * _sample_factor)
FROM visits_v1
SAMPLE 10000000
┌─sum(multiply(PageViews, _sample_factor))─┐
│ 6738137 │
└──────────────────────────────────────────┘
1 rows in set. Elapsed: 0.014 sec. Processed 1.68 million rows, 6.71 MB (123.55 million
rows/s., 494.20 MB/s.)
   
   下一个示例演示如何计算访问总数:
hdp-1 :) select sum(_sample_factor) from visits_v1 sample 10000000;
SELECT sum(_sample_factor)
FROM visits_v1
SAMPLE 10000000
┌─sum(_sample_factor)─┐
│ 1676861 │
└─────────────────────┘
1 rows in set. Elapsed: 0.003 sec. Processed 1.68 million rows, 1.68 MB (529.35 million
rows/s., 529.35 MB/s.)
   
   下面的示例显示了如何计算平均会话持续时间。 请注意，您不需要使用相对系数来计算平均值。
hdp-1 :) select avg(Duration) from visits_v1 sample 10000000;
SELECT avg(Duration)
FROM visits_v1
SAMPLE 10000000
┌──────avg(Duration)─┐
│ 359.92117176080785 │
└────────────────────┘
1 rows in set. Elapsed: 0.011 sec. Processed 1.68 million rows, 6.71 MB (148.60 million
rows/s., 594.38 MB/s.)

   SAMPLE K OFFSET M
   这里 k 和 m 是从0到1的数字。 示例如下所示。
   示例1
SAMPLE 1/10
   在此示例中，示例是所有数据的十分之一:
[++------------]
   示例2
SAMPLE 1/10 OFFSET 1/2
   这里，从数据的后半部分1/2 取出10％的样本。如果10%超出自动截断
   4).JOIN子句
   array join
hdp-1 :) use default;
USE default
Ok.
0 rows in set. Elapsed: 0.001 sec.

hdp-1 :) create table query_v1 (title String, value Array(UInt8))engine=Log;
CREATE TABLE query_v1
(
`title` String,
`value` Array(UInt8)
)
ENGINE = Log
Ok.
0 rows in set. Elapsed: 0.002 sec.

hdp-1 :) show tables;
SHOW TABLES
┌─name─────────────────┐
│ UUID_TEST │
│ dfv_v1 │
│ hot_cold_table │
│ hot_cold_table_new │
│ jbod_table │
│ jdbc_example │
│ mt_table │
│ mt_table2 │
│ partition_v1 │
│ partition_v2 │
│ query_v1 │
│ r1 │
│ replace_table │
│ summing_table │
│ summing_table_nested │
│ tmp_v1 │
│ ttl_table_v1 │
└──────────────────────┘
17 rows in set. Elapsed: 0.001 sec.

hdp-1 :) insert into query_v1 values('student',[1,2,3]),('teacher',[4,5]),('suguan',[]);
INSERT INTO query_v1 VALUES
Ok.
3 rows in set. Elapsed: 0.004 sec.

hdp-1 :) select * from query_v1;
SELECT *
FROM query_v1
┌─title───┬─value───┐
│ student │ [1,2,3] │
│ teacher │ [4,5] │
│ suguan │ [] │
└─────────┴─────────┘
3 rows in set. Elapsed: 0.001 sec.

hdp-1 :) select title,value from query_v1 array join value;
SELECT
title,
value
FROM query_v1
ARRAY JOIN value
┌─title───┬─value─┐
│ student │ 1 │
│ student │ 2 │
│ student │ 3 │
│ teacher │ 4 │
│ teacher │ 5 │
└─────────┴───────┘
5 rows in set. Elapsed: 0.002 sec.

hdp-1 :) select title,value,v from query_v1 array join value as v;
SELECT
title,
value,
v
FROM query_v1
ARRAY JOIN value AS v
┌─title───┬─value───┬─v─┐
│ student │ [1,2,3] │ 1 │
│ student │ [1,2,3] │ 2 │
│ student │ [1,2,3] │ 3 │
│ teacher │ [4,5] │ 4 │
│ teacher │ [4,5] │ 5 │
└─────────┴─────────┴───┘
5 rows in set. Elapsed: 0.002 sec.

   arrayMap(func, arr1, …)
   Returns an array obtained from the original application of the func function to each element in the arr
array.
   Examples:
SELECT arrayMap(x -> (x + 2), [1, 2, 3]) as res;
┌─res─────┐
│ [3,4,5] │
└─────────┘
   
   The following example shows how to create a tuple of elements from different arrays:
SELECT arrayMap((x, y) -> (x, y), [1, 2, 3], [4, 5, 6]) AS res
┌─res─────────────────┐
│ [(1,4),(2,5),(3,6)] │
└─────────────────────┘
   Note that the arrayMap is a higher-order function. You must pass a lambda function to it as the first
argument, and it can’t be omitted.
hdp-1 :) select arrayMap(x->x*2,value) from query_v1;
SELECT arrayMap(x -> (x * 2), value)
FROM query_v1
┌─arrayMap(lambda(tuple(x), multiply(x, 2)), value)─┐
│ [2,4,6] │
│ [8,10] │
│ [] │
└───────────────────────────────────────────────────┘
3 rows in set. Elapsed: 0.002 sec.

hdp-1 :) select title,value,v,arrayMap(x->x*2,value) as mapv,v_1 from query_v1 left array
join value as v,mapv as v_1;
SELECT
title,
value,
v,
arrayMap(x -> (x * 2), value) AS mapv,
v_1
FROM query_v1
LEFT ARRAY JOIN
value AS v,
mapv AS v_1
┌─title───┬─value───┬─v─┬─mapv────┬─v_1─┐
│ student │ [1,2,3] │ 1 │ [2,4,6] │ 2 │
│ student │ [1,2,3] │ 2 │ [2,4,6] │ 4 │
│ student │ [1,2,3] │ 3 │ [2,4,6] │ 6 │
│ teacher │ [4,5] │ 4 │ [8,10] │ 8 │
│ teacher │ [4,5] │ 5 │ [8,10] │ 10 │
│ suguan │ [] │ 0 │ [] │ 0 │
└─────────┴─────────┴───┴─────────┴─────┘
6 rows in set. Elapsed: 0.002 sec.

hdp-1 :) select title,value,v from query_v1 left array join value as v;
SELECT
title,
value,
v
FROM query_v1
LEFT ARRAY JOIN value AS v
┌─title───┬─value───┬─v─┐
│ student │ [1,2,3] │ 1 │
│ student │ [1,2,3] │ 2 │
│ student │ [1,2,3] │ 3 │
│ teacher │ [4,5] │ 4 │
│ teacher │ [4,5] │ 5 │
│ suguan │ [] │ 0 │
└─────────┴─────────┴───┘
   
   JOIN
   三张表：
create table join_tb1 (id UInt8,name String,time DateTime) engine=Log;
insert into join_tb1 values(1,'ClickHouse','2020-02-01 12:00:00');
insert into join_tb1 values(2,'Spark','2020-02-01 12:30:00');
insert into join_tb1 values(3,'ElasticSearch','2020-02-01 13:00:00');
insert into join_tb1 values(4,'HBase','2020-02-01 13:30:00');
insert into join_tb1 (name,time)values('ClickHouse','2020-02-01 12:00:00');
insert into join_tb1 (name,time)values('Spark','2020-02-01 12:00:00');

create table join_tb2 (id UInt8, rate UInt8, time DateTime) engine=Log;
insert into join_tb2 values(1,100,'2020-05-02 10:00:00');
insert into join_tb2 values(2,90,'2020-05-02 10:01:00');
insert into join_tb2 values(3,80,'2020-05-02 10:02:00');
insert into join_tb2 values(5,70,'2020-05-02 10:03:00');
insert into join_tb2 values(6,60,'2020-05-02 10:04:00');

create table join_tb3 (id UInt8, star UInt8) engine=Log;
insert into join_tb3 values(1,1000);
insert into join_tb3 values(2,900);

SELECT *
FROM join_tb1
┌─id─┬─name──────────┬────────────────time─┐
│ 1 │ ClickHouse │ 2020-02-01 12:00:00 │
│ 2 │ Spark │ 2020-02-01 12:30:00 │
│ 3 │ ElasticSearch │ 2020-02-01 13:00:00 │
└────┴───────────────┴─────────────────────┘
┌─id─┬─name───────┬────────────────time─┐
│ 4 │ HBase │ 2020-02-01 13:30:00 │
│ 0 │ ClickHouse │ 2020-02-01 12:00:00 │
│ 0 │ Spark │ 2020-02-01 12:00:00 │
└────┴────────────┴─────────────────────┘

SELECT *
FROM join_tb2
┌─id─┬─rate─┬────────────────time─┐
│ 1 │ 100 │ 2020-05-02 10:00:00 │
│ 2 │ 90 │ 2020-05-02 10:01:00 │
└────┴──────┴─────────────────────┘
┌─id─┬─rate─┬────────────────time─┐
│ 3 │ 80 │ 2020-05-02 10:02:00 │
│ 5 │ 70 │ 2020-05-02 10:03:00 │
│ 6 │ 60 │ 2020-05-02 10:04:00 │
└────┴──────┴─────────────────────┘

SELECT *
FROM join_tb3
┌─id─┬─star─┐
│ 1 │ 232 │
└────┴──────┘
┌─id─┬─star─┐
│ 2 │ 132 │
└────┴──────┘
   
   查询：ALL
hdp-1 :) select a.id,a.name,b.rate from join_tb1 as a all inner join join_tb2 as b on
a.id=b.id;
SELECT
a.id,
a.name,
b.rate
FROM join_tb1 AS a
ALL INNER JOIN join_tb2 AS b ON a.id = b.id
┌─id─┬─name──────────┬─rate─┐
│ 1 │ ClickHouse │ 100 │
│ 1 │ ClickHouse │ 104 │
│ 2 │ Spark │ 90 │
│ 3 │ ElasticSearch │ 80 │
└────┴───────────────┴──────┘
4 rows in set. Elapsed: 0.003 sec.

   ANY
hdp-1 :) select a.id,a.name,b.rate from join_tb1 as a any inner join join_tb2 as b on
a.id=b.id;
SELECT
a.id,
a.name,
b.rate
FROM join_tb1 AS a
ANY INNER JOIN join_tb2 AS b ON a.id = b.id
┌─id─┬─name──────────┬─rate─┐
│ 1 │ ClickHouse │ 100 │
│ 2 │ Spark │ 90 │
│ 3 │ ElasticSearch │ 80 │
└────┴───────────────┴──────┘
3 rows in set. Elapsed: 0.004 sec.

   ASOF
hdp-1 :) select a.id,a.name,b.rate,a.time,b.time from join_tb1 as a any inner join join_tb2
as b on a.id=b.id;
SELECT
a.id,
a.name,
b.rate,
a.time,
b.time
FROM join_tb1 AS a
ANY INNER JOIN join_tb2 AS b ON a.id = b.id
┌─id─┬─name──────────┬─rate─┬────────────────time─┬──────────────b.time─┐
│ 1 │ ClickHouse │ 100 │ 2020-02-01 12:00:00 │ 2020-05-02 10:00:00 │
│ 2 │ Spark │ 90 │ 2020-02-01 12:30:00 │ 2020-05-02 10:01:00 │
│ 3 │ ElasticSearch │ 80 │ 2020-02-01 13:00:00 │ 2020-05-02 10:02:00 │
└────┴───────────────┴──────┴─────────────────────┴─────────────────────┘
3 rows in set. Elapsed: 0.003 sec.

hdp-1 :) select a.id,a.name,b.rate,a.time,b.time from join_tb1 as a asof inner join join_tb2
as b on a.id=b.id and a.time <= b.time;
SELECT
a.id,
a.name,
b.rate,
a.time,
b.time
FROM join_tb1 AS a
ASOF INNER JOIN join_tb2 AS b ON (a.id = b.id) AND (a.time <= b.time)
┌─id─┬─name──────────┬─rate─┬────────────────time─┬──────────────b.time─┐
│ 1 │ ClickHouse │ 100 │ 2020-02-01 12:00:00 │ 2020-05-02 10:00:00 │
│ 2 │ Spark │ 90 │ 2020-02-01 12:30:00 │ 2020-05-02 10:01:00 │
│ 3 │ ElasticSearch │ 80 │ 2020-02-01 13:00:00 │ 2020-05-02 10:02:00 │
└────┴───────────────┴──────┴─────────────────────┴─────────────────────┘
3 rows in set. Elapsed: 0.003 sec.

   Join通过使用一个或多个表的公共值合并来自一个或多个表的列来生成新表。 它是支持SQL的数据库中的常见操作，
它对应于 关系代数 加入。 一个表连接的特殊情况通常被称为 “self-join”.
   语法:
SELECT <expr_list>
FROM <left_table>
[GLOBAL] [INNER|LEFT|RIGHT|FULL|CROSS] [OUTER|SEMI|ANTI|ANY|ASOF] JOIN <right_table>
(ON <expr_list>)|(USING <column_list>) ...
   从表达式 ON 从子句和列 USING 子句被称为 “join keys”. 除非另有说明，加入产生一个 笛卡尔积 从具有匹配的行
"join keys"，这可能会产生比源表更多的行的结果。
   支持的联接类型
   所有标准 SQL JOIN 支持类型:
       INNER JOIN，只返回匹配的行。
	   LEFT OUTER JOIN，除了匹配的行之外，还返回左表中的非匹配行。
       RIGHT OUTER JOIN，除了匹配的行之外，还返回右表中的非匹配行。
       FULL OUTER JOIN，除了匹配的行之外，还会返回两个表中的非匹配行。
       CROSS JOIN，产生整个表的笛卡尔积, “join keys” 是 不 指定。
   JOIN 没有指定类型暗指 INNER. 关键字 OUTER 可以安全地省略。 替代语法 CROSS JOIN 在指定多个表 FROM 用逗
号分隔。
   ClickHouse中提供的其他联接类型:
       LEFT SEMI JOIN 和 RIGHT SEMI JOIN,白名单 “join keys”，而不产生笛卡尔积。
       LEFT ANTI JOIN 和 RIGHT ANTI JOIN，黑名单 “join keys”，而不产生笛卡尔积。
	   LEFT ANY JOIN, RIGHT ANY JOIN and INNER ANY JOIN, partially (for opposite side of LEFT and RIGHT) or
completely (for INNER and FULL) disables the cartesian product for standard JOIN types.
       ASOF JOIN and LEFT ASOF JOIN, joining sequences with a non-exact match. ASOF JOIN usage is described
below.
   严格
   注
   可以使用以下方式复盖默认的严格性值 join_default_strictness 设置。
   Also the behavior of ClickHouse server for ANY JOIN operations depends on the
any_join_distinct_right_table_keys setting.
   ASOF加入使用
   ASOF JOIN 当您需要连接没有完全匹配的记录时非常有用。
   算法需要表中的特殊列。 本专栏:
       必须包含有序序列。
       可以是以下类型之一: Int，UInt, 浮动, 日期, 日期时间, 十进制.
       不能是唯一的列 JOIN
   语法 ASOF JOIN ... ON:
SELECT expressions_list
FROM table_1
ASOF LEFT JOIN table_2
ON equi_cond AND closest_match_cond
   您可以使用任意数量的相等条件和恰好一个最接近的匹配条件。 例如, SELECT count() FROM table_1 ASOF LEFT
JOIN table_2 ON table_1.a == table_2.b AND table_2.t <= table_1.t.
   支持最接近匹配的条件: >, >=, <, <=.
   语法 ASOF JOIN ... USING:
SELECT expressions_list
FROM table_1
ASOF JOIN table_2
USING (equi_column1, ... equi_columnN, asof_column)
   ASOF JOIN 用途 equi_columnX 对于加入平等和 asof_column 用于加入与最接近的比赛 table_1.asof_column >=
table_2.asof_column 条件。 该 asof_column 列总是在最后一个 USING 条款
   例如，请考虑下表:
         table_1                        table_2
event | ev_time | user_id 		  event | ev_time | user_id
----------|---------|---------- ----------|---------|----------
          ...                       	     ...
event_1_1 | 12:00 | 42 			event_2_1 | 11:59 | 42
          ...                   event_2_2 | 12:30 | 42
event_1_2 | 13:00 | 42 			event_2_3 | 13:00 | 42
          ...                                ...
   ASOF JOIN 可以从用户事件的时间戳 table_1 并找到一个事件 table_2 其中时间戳最接近事件的时间戳 table_1 对应
于最接近的匹配条件。 如果可用，则相等的时间戳值是最接近的值。 在这里，该 user_id 列可用于连接相等和
ev_time 列可用于在最接近的匹配加入。 在我们的例子中, event_1_1 可以加入 event_2_1 和 event_1_2 可以加入
event_2_3，但是 event_2_2 不能加入。
   注
   ASOF 加入是 不 支持在 加入我们 表引擎。
   分布式联接
   有两种方法可以执行涉及分布式表的join:
       当使用正常 JOIN，将查询发送到远程服务器。 为了创建正确的表，在每个子查询上运行子查询，并使用此表执
行联接。 换句话说，在每个服务器上单独形成右表。
       使用时 GLOBAL ... JOIN，首先请求者服务器运行一个子查询来计算正确的表。 此临时表将传递到每个远程服务
器，并使用传输的临时数据对其运行查询。
   使用时要小心 GLOBAL. 有关详细信息，请参阅 分布式子查询 科。
   使用建议
   处理空单元格或空单元格
   在连接表时，可能会出现空单元格。 设置 join_use_nulls 定义ClickHouse如何填充这些单元格。
   如果 JOIN 键是 可为空 字段，其中至少有一个键具有值的行 NULL 没有加入。
   语法
   在指定的列 USING 两个子查询中必须具有相同的名称，并且其他列必须以不同的方式命名。 您可以使用别名更改子
查询中的列名。
   该 USING 子句指定一个或多个要联接的列，这将建立这些列的相等性。 列的列表设置不带括号。 不支持更复杂的连
接条件。
   语法限制
   对于多个 JOIN 单个子句 SELECT 查询:
       通过以所有列 * 仅在联接表时才可用，而不是子查询。
       该 PREWHERE 条款不可用。
   为 ON, WHERE，和 GROUP BY 条款:
       任意表达式不能用于 ON, WHERE，和 GROUP BY 子句，但你可以定义一个表达式 SELECT 子句，然后通过别
名在这些子句中使用它。
   性能
   当运行 JOIN，与查询的其他阶段相关的执行顺序没有优化。 连接（在右表中搜索）在过滤之前运行 WHERE 和聚集
之前。
   每次使用相同的查询运行 JOIN，子查询再次运行，因为结果未缓存。 为了避免这种情况，使用特殊的 加入我们 表引
擎，它是一个用于连接的准备好的数组，总是在RAM中。
   在某些情况下，使用效率更高 IN 而不是 JOIN.
   如果你需要一个 JOIN 对于连接维度表（这些是包含维度属性的相对较小的表，例如广告活动的名称）， JOIN 由于
每个查询都会重新访问正确的表，因此可能不太方便。 对于这种情况下，有一个 “external dictionaries” 您应该使用
的功能 JOIN. 有关详细信息，请参阅 外部字典 科。
   内存限制
   默认情况下，ClickHouse使用 哈希联接 算法。 ClickHouse采取 `` 并在RAM中为其创建哈希表。 在某个内存消耗阈
值之后，ClickHouse回退到合并联接算法。
   如果需要限制联接操作内存消耗，请使用以下设置:
       max_rows_in_join — Limits number of rows in the hash table.
	   max_bytes_in_join — Limits size of the hash table.
   当任何这些限制达到，ClickHouse作为 join_overflow_mode 设置指示。
   例子
   示例:
SELECT
CounterID,
hits,
visits
FROM
(
SELECT
CounterID,
count() AS hits
FROM test.hits
GROUP BY CounterID
) ANY LEFT JOIN
(
SELECT
CounterID,
sum(Sign) AS visits
FROM test.visits
GROUP BY CounterID
) USING CounterID
ORDER BY hits DESC
LIMIT 10
┌─CounterID─┬───hits─┬─visits─┐
│ 1143050 │ 523264 │ 13665 │
│ 731962 │ 475698 │ 102716 │
│ 722545 │ 337212 │ 108187 │
│ 722889 │ 252197 │ 10547 │
│ 2237260 │ 196036 │ 9522 │
│ 23057320 │ 147211 │ 7689 │
│ 722818 │ 90109 │ 17847 │
│ 48221 │ 85379 │ 4652 │
│ 19762435 │ 77807 │ 7026 │
│ 722884 │ 77492 │ 11056 │
└───────────┴────────┴────────┘

   拆分分析：
hdp-1 :) select CounterID as id, count() as hits from hits_v1 group by id limit 10;
SELECT
CounterID AS id,
count() AS hits
FROM hits_v1
GROUP BY id
LIMIT 10
┌───────id─┬─hits─┐
│ 24141121 │ 4 │
│ 31790479 │ 2 │
│ 17424666 │ 1 │
│ 29229146 │ 1 │
│ 8325557 │ 2 │
│ 2314381 │ 26 │
│ 899083 │ 2 │
│ 19151207 │ 96 │
│ 31138002 │ 7 │
│ 129995 │ 4 │
└──────────┴──────┘
10 rows in set. Elapsed: 0.042 sec. Processed 8.87 million rows, 35.50 MB (209.50 million
rows/s., 837.99 MB/s.)

hdp-1 :) select CounterID as id,sum(Sign) as visits from visits_v1 group by id limit 10;
SELECT
CounterID AS id,
sum(Sign) AS visits
FROM visits_v1
GROUP BY id
LIMIT 10
┌───────id─┬─visits─┐
│ 1602763 │ 10 │
│ 205593 │ 1 │
│ 406018 │ 1 │
│ 1398990 │ 1 │
│ 17891807 │ 1 │
│ 24614464 │ 1 │
│ 14339903 │ 3 │
│ 9991977 │ 5 │
│ 31934585 │ 1 │
│ 15525311 │ 3 │
└──────────┴────────┘

--LEFT JOIN 各种join
hdp-1 :) select * from (select CounterID as id, count() as hits from hits_v1 group by id
limit 10) as a left join (select CounterID as id,sum(Sign) as visits from visits_v1 group by
id limit 10) as b on a.id = b.id;
SELECT *
FROM
(
SELECT
CounterID AS id,
count() AS hits
FROM hits_v1
GROUP BY id
 LIMIT 10
) AS a
LEFT JOIN
(
SELECT
CounterID AS id,
sum(Sign) AS visits
FROM visits_v1
GROUP BY id
LIMIT 10
) AS b ON a.id = b.id
┌───────id─┬─hits─┬─b.id─┬─visits─┐
│ 24141121 │ 4 │ 0 │ 0 │
│ 31790479 │ 2 │ 0 │ 0 │
│ 17424666 │ 1 │ 0 │ 0 │
│ 29229146 │ 1 │ 0 │ 0 │
│ 8325557 │ 2 │ 0 │ 0 │
│ 2314381 │ 26 │ 0 │ 0 │
│ 899083 │ 2 │ 0 │ 0 │
│ 19151207 │ 96 │ 0 │ 0 │
│ 31138002 │ 7 │ 0 │ 0 │
│ 129995 │ 4 │ 0 │ 0 │
└──────────┴──────┴──────┴────────┘
   5).PREWHERE 子句
select WatchID,Title,GoodEvent from hits_v1 where JavaEnable=1;
6535088 rows in set. Elapsed: 40.853 sec. Processed 8.87 million rows, 863.90 MB (217.22
thousand rows/s., 21.15 MB/s.)

select WatchID,Title,GoodEvent from hits_v1 prewhere JavaEnable=1;
6535088 rows in set. Elapsed: 22.150 sec. Processed 8.87 million rows, 863.90 MB (400.62
thousand rows/s., 39.00 MB/s.)
SET optimize_move_to_prewhere = 0
Ok.
0 rows in set. Elapsed: 0.011 sec.

hdp-1 :) select WatchID,Title,GoodEvent from hits_v1 where JavaEnable=1;
6535088 rows in set. Elapsed: 35.728 sec. Processed 8.87 million rows, 864.55 MB (248.38
thousand rows/s., 24.20 MB/s.)

hdp-1 :) select WatchID,Title,GoodEvent from hits_v1 prewhere JavaEnable=1;
6535088 rows in set. Elapsed: 32.021 sec. Processed 8.87 million rows, 863.90 MB (277.13
thousand rows/s., 26.98 MB/s.)
   Prewhere是更有效地进行过滤的优化。 默认情况下，即使在 PREWHERE 子句未显式指定。 它也会自动移动
WHERE 条件到prewhere阶段。 PREWHERE 子句只是控制这个优化，如果你认为你知道如何做得比默认情况下更好
才去控制它。
   使用prewhere优化，首先只读取执行prewhere表达式所需的列。 然后读取运行其余查询所需的其他列，但只读取
prewhere表达式所在的那些块 “true” 至少对于一些行。 如果有很多块，其中prewhere表达式是 “false” 对于所有行
和prewhere需要比查询的其他部分更少的列，这通常允许从磁盘读取更少的数据以执行查询。
   手动控制Prewhere
   该子句具有与 WHERE 相同的含义，区别在于从表中读取数据。 当手动控制 PREWHERE 对于查询中的少数列使用的
过滤条件，但这些过滤条件提供了强大的数据过滤。 这减少了要读取的数据量。
   查询可以同时指定 PREWHERE 和 WHERE. 在这种情况下, PREWHERE 先于 WHERE.
   如果 optimize_move_to_prewhere 设置为0，启发式自动移动部分表达式 WHERE 到 PREWHERE 被禁用。
   限制
   PREWHERE 只有支持 *MergeTree 族系列引擎的表。
   vi /var/log/clickhouse-server/clickhouse-server.log
2020.10.24 13:36:24.818179 [ 13472 ] {6f7289cb-4332-4cfd-a1ac-aa98025bf56f} <Debug>
InterpreterSelectQuery: MergeTreeWhereOptimizer: condition "JavaEnable = 1" moved to
PREWHERE
   6).WHERE
   WHERE 子句允许过滤从 FROM 子句 SELECT.
   如果有一个 WHERE 子句，它必须包含一个表达式与 UInt8 类型。 这通常是一个带有比较和逻辑运算符的表达式。
此表达式计算结果为0的行将从进一步的转换或结果中解释出来。
   WHERE 如果基础表引擎支持，则根据使用索引和分区修剪的能力评估表达式。
   注
   有一个叫做过滤优化 prewhere 的东西.
   7).GROUP BY子句
   GROUP BY 子句将 SELECT 查询结果转换为聚合模式，其工作原理如下:
       GROUP BY 子句包含表达式列表（或单个表达式 -- 可以认为是长度为1的列表）。 这份名单充当 “grouping
key”，而每个单独的表达式将被称为 “key expressions”.
       在所有的表达式在 SELECT, HAVING，和 ORDER BY 子句中 必须 基于键表达式进行计算 或 上 聚合函数 在非键
表达式（包括纯列）上。 换句话说，从表中选择的每个列必须用于键表达式或聚合函数内，但不能同时使用。
       聚合结果 SELECT 查询将包含尽可能多的行，因为有唯一值 “grouping key” 在源表中。 通常这会显着减少行
数，通常是数量级，但不一定：如果所有行数保持不变 “grouping key” 值是不同的。
   
   注
   还有一种额外的方法可以在表上运行聚合。 如果查询仅在聚合函数中包含表列，则 GROUP BY 可以省略，并且通过
一个空的键集合来假定聚合。 这样的查询总是只返回一行。
   空处理
对于分组，ClickHouse解释 NULL 作为一个值，并且 NULL==NULL. 它不同于 NULL 在大多数其他上下文中的处理
方式。
   这里有一个例子来说明这意味着什么。
   假设你有一张表:
┌─x─┬────y─┐
│ 1 │ 2 │
│ 2 │ ᴺᵁᴸᴸ │
│ 3 │ 2 │
│ 3 │ 3 │
│ 3 │ ᴺᵁᴸᴸ │
└───┴──────┘
   查询 SELECT sum(x), y FROM t_null_big GROUP BY y 结果:
┌─sum(x)─┬────y─┐
│ 4 │ 2 │
│ 3 │ 3 │
│ 5 │ ᴺᵁᴸᴸ │
└────────┴──────┘

   你可以看到 GROUP BY 为 y = NULL 总结 x，仿佛 NULL 是这个值。
   如果你通过几个键 GROUP BY，结果会给你选择的所有组合，就好像 NULL 是一个特定的值。
   WITH TOTAL 修饰符
   如果 WITH TOTALS 被指定，将计算另一行。 此行将具有包含默认值（零或空行）的关键列，以及包含跨所有行计算
值的聚合函数列（ “total” 值）。
   这个额外的行仅产生于 JSON, TabSeparated，和 Pretty* 格式，与其他行分开:
       在 JSON* 格式，这一行是作为一个单独的输出 ‘totals’ 字段。
       在 TabSeparated* 格式，该行位于主结果之后，前面有一个空行（在其他数据之后）。
       在 Pretty* 格式时，该行在主结果之后作为单独的表输出。
       在其他格式中，它不可用。
   WITH TOTALS 可以以不同的方式运行时 HAVING 是存在的。 该行为取决于 totals_mode 设置。
   配置总和处理
   默认情况下, totals_mode = 'before_having'. 在这种情况下, ‘totals’ 是跨所有行计算，包括那些不通过具有和
max_rows_to_group_by.
   其他替代方案仅包括通过具有在 ‘totals’，并与设置不同的行为 max_rows_to_group_by 和
group_by_overflow_mode = 'any'.
   after_having_exclusive – Don't include rows that didn't pass through max_rows_to_group_by. 换句话说, ‘totals’
将有少于或相同数量的行，因为它会 max_rows_to_group_by 被省略。
   after_having_inclusive – Include all the rows that didn't pass through ‘max_rows_to_group_by’ 在 ‘totals’. 换句话
说, ‘totals’ 将有多个或相同数量的行，因为它会 max_rows_to_group_by 被省略。
   after_having_auto – Count the number of rows that passed through HAVING. If it is more than a certain
amount (by default, 50%), include all the rows that didn't pass through ‘max_rows_to_group_by’ 在 ‘totals’. 否
则，不包括它们。
   totals_auto_threshold – By default, 0.5. The coefficient for after_having_auto.
   如果 max_rows_to_group_by 和 group_by_overflow_mode = 'any' 不使用，所有的变化 after_having 是相同的，
你可以使用它们中的任何一个（例如, after_having_auto).
   您可以使用 WITH TOTALS 在子查询中，包括在子查询 JOIN 子句（在这种情况下，将各自的总值合并）。
   例子
   示例:
SELECT
count(),
median(FetchTiming > 60 ? 60 : FetchTiming),
count() - sum(Refresh)
FROM hits
   但是，与标准SQL相比，如果表没有任何行（根本没有任何行，或者使用 WHERE 过滤之后没有任何行），则返回一
个空结果，而不是来自包含聚合函数初始值的行。
   相对于MySQL（并且符合标准SQL），您无法获取不在键或聚合函数（常量表达式除外）中的某些列的某些值。 要
解决此问题，您可以使用 ‘any’ 聚合函数（获取第一个遇到的值）或 ‘min/max’.
   示例:
SELECT
domainWithoutWWW(URL) AS domain,
count(),
any(Title) AS title -- getting the first occurred page header for each domain.
FROM hits
GROUP BY domain
   对于遇到的每个不同的键值, GROUP BY 计算一组聚合函数值。
   GROUP BY 不支持数组列。
   不能将常量指定为聚合函数的参数。 示例: sum(1). 相反，你可以摆脱常数。 示例: count().
   实现细节
   聚合是面向列的 DBMS 最重要的功能之一，因此它的实现是ClickHouse中最优化的部分之一。 默认情况下，聚合使
用哈希表在内存中完成。 它有 40+ 的特殊化自动选择取决于 “grouping key” 数据类型。
   在外部存储器中分组
   您可以启用将临时数据转储到磁盘以限制内存使用期间 GROUP BY. 该 max_bytes_before_external_group_by 设置
确定倾销的阈值RAM消耗 GROUP BY 临时数据到文件系统。 如果设置为0（默认值），它将被禁用。
   使用时 max_bytes_before_external_group_by，我们建议您设置 max_memory_usage 大约两倍高。 这是必要的，
因为聚合有两个阶段：读取数据和形成中间数据（1）和合并中间数据（2）。 将数据转储到文件系统只能在阶段1中
发生。 如果未转储临时数据，则阶段2可能需要与阶段1相同的内存量。
   例如，如果 max_memory_usage 设置为10000000000，你想使用外部聚合，这是有意义的设置
max_bytes_before_external_group_by 到10000000000，和 max_memory_usage 到20000000000。 当触发外部
聚合（如果至少有一个临时数据转储）时，RAM的最大消耗仅略高于 max_bytes_before_external_group_by.
   通过分布式查询处理，在远程服务器上执行外部聚合。 为了使请求者服务器只使用少量的RAM，设置
distributed_aggregation_memory_efficient 到1。
   当合并数据刷新到磁盘时，以及当合并来自远程服务器的结果时， distributed_aggregation_memory_efficient 设
置被启用，消耗高达 1/256 * the_number_of_threads 从RAM的总量。
   当启用外部聚合时，如果数据量小于 max_bytes_before_external_group_by (例如数据没有被 flushed), 查询执行速
度和不在外部聚合的速度一样快. 如果临时数据被flushed到外部存储, 执行的速度会慢几倍 (大概是三倍).
   如果你有一个 ORDER BY 用一个 LIMIT 后 GROUP BY，然后使用的RAM的量取决于数据的量 LIMIT，不是在整个
表。 但如果 ORDER BY 没有 LIMIT，不要忘记启用外部排序 (max_bytes_before_external_sort).
   8).LIMIT BY子句
   与查询 LIMIT n BY expressions 子句选择第一个 n 每个不同值的行 expressions. LIMIT BY 可以包含任意数量的 表达
式.
   ClickHouse支持以下语法变体:
       LIMIT [offset_value, ]n BY expressions
       LIMIT n OFFSET offset_value BY expressions
   在查询处理过程中，ClickHouse会选择按排序键排序的数据。 排序键使用以下命令显式设置 ORDER BY 子句或隐式
作为表引擎的属性。 然后ClickHouse应用 LIMIT n BY expressions 并返回第一 n 每个不同组合的行 expressions. 如
果 OFFSET 被指定，则对于每个数据块属于一个不同的组合 expressions，ClickHouse跳过 offset_value 从块开始的
行数，并返回最大值 n 行的结果。 如果 offset_value 如果数据块中的行数大于数据块中的行数，ClickHouse将从该
块返回零行。
   注
   LIMIT BY 是不相关的 LIMIT. 它们都可以在同一个查询中使用。
   例
   样例表:
CREATE TABLE limit_by(id Int, val Int) ENGINE = Memory;
INSERT INTO limit_by VALUES (1, 10), (1, 11), (1, 12), (2, 20), (2, 21);
   查询
SELECT * FROM limit_by ORDER BY id, val LIMIT 2 BY id
┌─id─┬─val─┐
│ 1 │ 10 │
│ 1 │ 11 │
│ 2 │ 20 │
│ 2 │ 21 │
└────┴─────┘
SELECT * FROM limit_by ORDER BY id, val LIMIT 1, 2 BY id
┌─id─┬─val─┐
│ 1 │ 11 │
│ 1 │ 12 │
│ 2 │ 21 │
└────┴─────┘
   该 SELECT * FROM limit_by ORDER BY id, val LIMIT 2 OFFSET 1 BY id 查询返回相同的结果。
   以下查询返回每个引用的前5个引用 domain, device_type 最多可与100行配对 (LIMIT n BY + LIMIT).
SELECT
domainWithoutWWW(URL) AS domain,
domainWithoutWWW(REFERRER_URL) AS referrer,
device_type,
count() cnt
FROM hits
GROUP BY domain, referrer, device_type
ORDER BY cnt DESC
LIMIT 5 BY domain, device_type
LIMIT 100   
   9).HAVING 子句
   允许过滤由 GROUP BY 生成的聚合结果. 它类似于 WHERE ，但不同的是 WHERE 在聚合之前执行，而 HAVING 之后
进行。
   可以从 SELECT 生成的聚合结果中通过他们的别名来执行 HAVING 子句。 或者 HAVING 子句可以筛选查询结果中未
返回的其他聚合的结果。
   限制
   HAVING 如果不执行聚合则无法使用。 使用 WHERE 则相反。
   10).SELECT 子句
   表达式 指定 SELECT 子句是在上述子句中的所有操作完成后计算的。 这些表达式的工作方式就好像它们应用于结果
中的单独行一样。 如果表达式 SELECT 子句包含聚合函数，然后ClickHouse将使用 GROUP BY 聚合参数应用在聚合
函数和表达式上。
   如果在结果中包含所有列，请使用星号 (*）符号。 例如, SELECT * FROM ....
   将结果中的某些列与 re2 正则表达式匹配，可以使用 COLUMNS 表达。
   COLUMNS('regexp')
   例如表:
CREATE TABLE default.col_names (aa Int8, ab Int8, bc Int8) ENGINE = TinyLog
   以下查询所有列名包含 a 。
SELECT COLUMNS('a') FROM col_names
┌─aa─┬─ab─┐
│ 1 │ 1 │
└────┴────┘
   所选列不按字母顺序返回。
   您可以使用多个 COLUMNS 表达式并将函数应用于它们。
   例如:
SELECT COLUMNS('a'), COLUMNS('c'), toTypeName(COLUMNS('c')) FROM col_names
┌─aa─┬─ab─┬─bc─┬─toTypeName(bc)─┐
│ 1 │ 1 │ 1 │ Int8 │
└────┴────┴────┴────────────────┘
   返回的每一列 COLUMNS 表达式作为单独的参数传递给函数。 如果函数支持其他参数，您也可以将其他参数传递给
函数。 使用函数时要小心，如果函数不支持传递给它的参数，ClickHouse将抛出异常。
   例如:
SELECT COLUMNS('a') + COLUMNS('c') FROM col_names
Received exception from server (version 19.14.1):
Code: 42. DB::Exception: Received from localhost:9000. DB::Exception: Number of arguments
for function plus doesn't match: passed 3, should be 2.
   该例子中, COLUMNS('a') 返回两列: aa 和 ab. COLUMNS('c') 返回 bc 列。 该 + 运算符不能应用于3个参数，因此
ClickHouse抛出一个带有相关消息的异常。
   匹配的列 COLUMNS 表达式可以具有不同的数据类型。 如果 COLUMNS 不匹配任何列，并且是在 SELECT 唯一的表
达式，ClickHouse则抛出异常。
   星号
   您可以在查询的任何部分使用星号替代表达式。进行查询分析、时，星号将展开为所有表的列（不包括
MATERIALIZED 和 ALIAS 列）。 只有少数情况下使用星号是合理的:
       创建转储表时。
       对于只包含几列的表，例如系统表。
       获取表中列的信息。 在这种情况下，设置 LIMIT 1. 但最好使用 DESC TABLE 查询。
       当对少量列使用 PREWHERE 进行强过滤时。
       在子查询中（因为外部查询不需要的列从子查询中排除）。
   在所有其他情况下，我们不建议使用星号，因为它只给你一个列DBMS的缺点，而不是优点。 换句话说，不建议使用
星号。
   极端值
   除结果之外，还可以获取结果列的最小值和最大值。 要做到这一点，设置 extremes 设置为1。 最小值和最大值是针
对数字类型、日期和带有时间的日期计算的。 对于其他类型列，输出默认值。
   分别的额外计算两行 – 最小值和最大值。 这额外的两行采用输出格式为 JSON, TabSeparated，和 Pretty* formats，
与其他行分开。 它们不以其他格式输出
   为 JSON* 格式时，极端值单独的输出在 ‘extremes’ 字段。 为 TabSeparated* 格式时，此行来的主要结果集后，然
后显示 ‘totals’ 字段。 它前面有一个空行（在其他数据之后）。 在 Pretty* 格式时，该行在主结果之后输出为一个单
独的表，然后显示 ‘totals’ 字段。
   极端值在 LIMIT 之前被计算，但在 LIMIT BY 之后被计算. 然而，使用 LIMIT offset, size， offset 之前的行都包含在
extremes. 在流请求中，结果还可能包括少量通过 LIMIT 过滤的行.
   备注
   您可以在查询的任何部分使用同义词 (AS 别名）。
   GROUP BY 和 ORDER BY 子句不支持位置参数。 这与MySQL相矛盾，但符合标准SQL。 例如, GROUP BY 1, 2 将被
理解为根据常量分组 (i.e. aggregation of all rows into one).
   实现细节
   如果查询省略 DISTINCT, GROUP BY ， ORDER BY ， IN ， JOIN 子查询，查询将被完全流处理，使用O(1)量的
RAM。 若未指定适当的限制，则查询可能会消耗大量RAM:
       max_memory_usage
	   max_rows_to_group_by
       max_rows_to_sort
       max_rows_in_distinct
       max_bytes_in_distinct
       max_rows_in_set
       max_bytes_in_set
       max_rows_in_join
       max_bytes_in_join
       max_bytes_before_external_sort
       max_bytes_before_external_group_by
   有关详细信息，请参阅部分 “Settings”. 可以使用外部排序（将临时表保存到磁盘）和外部聚合。
   11).DISTINCT子句
   如果 SELECT DISTINCT 被声明，则查询结果中只保留唯一行。 因此，在结果中所有完全匹配的行集合中，只有一行
被保留。
   空处理
   DISTINCT 适用于 NULL 就好像 NULL 是一个特定的值，并且 NULL==NULL. 换句话说，在 DISTINCT 结果，不同的
组合 NULL 仅发生一次。 它不同于 NULL 在大多数其他情况中的处理方式。
   替代办法
   通过应用可以获得相同的结果 GROUP BY 在同一组值指定为 SELECT 子句，并且不使用任何聚合函数。 但与
GROUP BY 有几个不同的地方:
       DISTINCT 可以与 GROUP BY 一起使用.
       当 ORDER BY 被省略并且 LIMIT 被定义时，在读取所需数量的不同行后立即停止运行。
	   数据块在处理时输出，而无需等待整个查询完成运行。
   限制
   DISTINCT 不支持当 SELECT 包含有数组的列。
   例子
   ClickHouse支持使用 DISTINCT 和 ORDER BY 在一个查询中的不同的列。 DISTINCT 子句在 ORDER BY 子句前被执
行。
   示例表:
┌─a─┬─b─┐
│ 2 │ 1 │
│ 1 │ 2 │
│ 3 │ 3 │
│ 2 │ 4 │
└───┴───┘
   当执行 SELECT DISTINCT a FROM t1 ORDER BY b ASC 来查询数据，我们得到以下结果:
┌─a─┐
│ 2 │
│ 1 │
│ 3 │
└───┘
   如果我们改变排序方向 SELECT DISTINCT a FROM t1 ORDER BY b DESC，我们得到以下结果:
┌─a─┐
│ 3 │
│ 1 │
│ 2 │
└───┘
   行 2, 4 排序前被切割。
   在编程查询时考虑这种实现特性。
   12).LIMIT
   LIMIT m 允许选择结果中起始的 m 行。
   LIMIT n, m 允许选择个 m 从跳过第一个结果后的行 n 行。 与 LIMIT m OFFSET n 语法是等效的。
   n 和 m 必须是非负整数。
   如果没有 ORDER BY 子句显式排序结果，结果的行选择可能是任意的和非确定性的。
   LIMIT … WITH TIES 修饰符
   如果为 LIMIT n[,m] 设置了 WITH TIES ，并且声明了 ORDER BY expr_list, you will get in result first n or n,m rows
and all rows with same ORDER BY fields values equal to row at position n for LIMIT n and m for LIMIT n,m.
   此修饰符可以与： ORDER BY … WITH FILL modifier 组合使用.
   例如以下查询：
SELECT * FROM (
SELECT number%50 AS n FROM numbers(100)
) ORDER BY n LIMIT 0,5
   返回
┌─n─┐
│ 0 │
│ 0 │
│ 1 │
│ 1 │
│ 2 │
└───┘
   单子执行了 WITH TIES 修饰符后
SELECT * FROM (
SELECT number%50 AS n FROM numbers(100)
) ORDER BY n LIMIT 0,5 WITH TIES
   则返回了以下的数据行
┌─n─┐
│ 0 │
│ 0 │
│ 1 │
│ 1 │
│ 2 │
│ 2 │
└───┘
   cause row number 6 have same value “2” for field n as row number 5
   13).UNION ALL子句
   你可以使用 UNION ALL 结合任意数量的 SELECT 来扩展其结果。 
   示例:
SELECT CounterID, 1 AS table, toInt64(count()) AS c
FROM test.hits
GROUP BY CounterID
UNION ALL

SELECT CounterID, 2 AS table, sum(Sign) AS c
FROM test.visits
GROUP BY CounterID
HAVING c > 0
   结果列通过它们的索引进行匹配（在内部的顺序 SELECT). 如果列名称不匹配，则从第一个查询中获取最终结果的名
称。
   对联合执行类型转换。 例如，如果合并的两个查询具有相同的字段与非-Nullable 和 Nullable 从兼容类型的类型，由
此产生的 UNION ALL 有一个 Nullable 类型字段。
   属于以下部分的查询 UNION ALL 不能用圆括号括起来。 ORDER BY 和 LIMIT 应用于单独的查询，而不是最终结果。
如果您需要将转换应用于最终结果，则可以将所有查询 UNION ALL 在子查询中 FROM 子句。
   限制
   只有 UNION ALL 支持。 UNION (UNION DISTINCT）不支持。 如果你需要 UNION DISTINCT，你可以写 SELECT
DISTINCT 子查询中包含 UNION ALL.
   实现细节
   属于 UNION ALL 的查询可以同时运行，并且它们的结果可以混合在一起。
   14).INTO OUTFILE 子句
   添加 INTO OUTFILE filename 子句（其中filename是字符串） SELECT query 将其输出重定向到客户端上的指定文
件。
   实现细节
       此功能是在可用 命令行客户端 和 clickhouse-local. 因此通过 HTTP接口 发送查询将会失败。
       如果具有相同文件名的文件已经存在，则查询将失败。
       默认值 输出格式 是 TabSeparated （就像在命令行客户端批处理模式中一样）。
   15).Format子句
   ClickHouse支持广泛的 序列化格式https://clickhouse.tech/docs/zh/interfaces/formats/ 可用于查询结果等。 有多
种方法可以选择格式化 SELECT 的输出，其中之一是指定 FORMAT format 在查询结束时以任何特定格式获取结果
集。
   特定的格式方便使用，与其他系统集成或增强性能。
   默认格式
   如果 FORMAT 被省略则使用默认格式，这取决于用于访问ClickHouse服务器的设置和接口。 为 HTTP接口 和 命令行
客户端 在批处理模式下，默认格式为 TabSeparated. 对于交互模式下的命令行客户端，默认格式为 PrettyCompact
(它生成紧凑的人类可读表)。
   实现细节
   使用命令行客户端时，数据始终以内部高效格式通过网络传递 (Native). 客户端独立解释 FORMAT 查询子句并格式化
数据本身（以减轻网络和服务器的额外负担）。